#include "hw_leds.h"
#include "driver_Mobvoi_includes.h"
#include "app_Mobvoi_includes.h"
#include "Mobvoi_external.h"
#include "coder.h"
#include "M510mp3_resample.h"
#include "M510reg.h"
#include "drv_audio.h"
#include "drv_system.h"
#include "math.h"

#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_DSP || CONFIG_ADC_CTRL_MODE == ADC_CTRL_BY_DSP
#include "drv_mailbox.h"
#endif

#define DAC_CLK_ADJUST_STEP 8192

static uint8_t s_audio_open_stat = 0;

uint32_t s_aud_dac_fraccoef[2][3] =
    {
        {AUDIO_DIV_441K_SLOW, AUDIO_DIV_441K, AUDIO_DIV_441K_FAST},
        {AUDIO_DIV_48K_SLOW, AUDIO_DIV_48K, AUDIO_DIV_48K_FAST}};

static t_dac_clk_state s_aud_dac_state = AUDIO_DAC_NORM;
static t_dac_clk_state s_current_aud_dac_state = AUDIO_DAC_NORM;

static uint32_t s_current_aud_dac_sample_rate = 0;

#if CONFIG_ADC_CTRL_MODE == ADC_CTRL_BY_MCU
AUDIO_CTRL_BLK audio_adc_ctrl_blk;
#endif
#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_MCU
AUDIO_CTRL_BLK audio_dac_ctrl_blk;
#endif

int16 g_soft_dig_gain = 256;
int16 g_soft_dig_goal = 256;

void aud_init(void)
{
    app_env_handle_t env_h = app_env_get_handle();

    system_apll_config(SYS_APLL_90p3168_MHZ);

    audio_init();
    if (env_h->env_cfg.system_para.system_flag & APP_ENV_SYS_FLAG_DAC_DIFFER)
        audio_dac_init(AUDIO_DAC_MODE_DIFFERENCE);
    else
        audio_dac_init(AUDIO_DAC_MODE_VCOM);
    audio_dac_sample_rate_set(48000);

    audio_adc_init(AUDIO_ADC_WIDTH_16, AUDIO_ADC_MODE_SINGLE_END);
    if (env_h->env_cfg.used == 1)
    {
        audio_adc_dig_gain_set(env_h->env_cfg.feature.vol_mic_dig & 0x3f);
        audio_adc_ana_gain_set(env_h->env_cfg.feature.vol_mic_ana & 0xf);
    }
    audio_adc_sample_rate_set(16000);
    audio_dac_ana_gain_set(0);

#if CONFIG_ADC_CTRL_MODE == ADC_CTRL_BY_MCU
    extern uint32_t _audio_rb_begin;
    void *adc_dma = dma_channel_malloc();
    audio_adc_ctrl_blk.data_buff = (uint8_t *)((uint32)&_audio_rb_begin);

    dma_channel_config(adc_dma,
                       DMA_REQ_AUDIO_ADC,
                       DMA_MODE_REPEAT,
                       (uint32_t)&REG_ANC_0x47,
                       (uint32_t)&REG_ANC_0x47,
                       DMA_ADDR_NO_CHANGE,
                       DMA_DATA_TYPE_SHORT,
                       (uint32_t)audio_adc_ctrl_blk.data_buff,
                       (uint32_t)audio_adc_ctrl_blk.data_buff + AUDIO_ADC_BUFF_LEN,
                       DMA_ADDR_AUTO_INCREASE,
                       DMA_DATA_TYPE_LONG,
                       AUDIO_ADC_BUFF_LEN);

    audio_adc_ctrl_blk.dma_handle = adc_dma;

    dma_channel_enable(adc_dma, 1);
    dma_channel_enable(adc_dma, 0);
#endif

#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_MCU
    extern uint32_t _audio_rb_begin;
    void *dac_dma = dma_channel_malloc();
    audio_dac_ctrl_blk.data_buff = (uint8_t *)((uint32)&_audio_rb_begin) + AUDIO_ADC_BUFF_LEN;

    dma_channel_config(dac_dma,
                       DMA_REQ_AUDIO_DAC,
                       DMA_MODE_REPEAT,
                       (uint32_t)audio_dac_ctrl_blk.data_buff,
                       (uint32_t)audio_dac_ctrl_blk.data_buff + AUDIO_DAC_BUFF_LEN,
                       DMA_ADDR_AUTO_INCREASE,
                       DMA_DATA_TYPE_LONG,
                       (uint32_t)&REG_ANC_0x4E,
                       (uint32_t)&REG_ANC_0x4E,
                       DMA_ADDR_NO_CHANGE,
                       DMA_DATA_TYPE_LONG,
                       AUDIO_DAC_BUFF_LEN);

    audio_dac_ctrl_blk.dma_handle = dac_dma;

    dma_channel_enable(dac_dma, 1);
    dma_channel_enable(dac_dma, 0);
#endif
}

int aud_dac_config(uint32_t freq, uint32_t channels, uint32_t bits_per_sample)
{
#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_MCU
    uint32_t apll_freq = (((freq / 11025) * 11025) == freq) ? SYS_APLL_90p3168_MHZ : SYS_APLL_98p3040_MHZ;
    uint32_t freq_changed = freq != s_current_aud_dac_sample_rate;

    (void)freq_changed;
#endif
    s_audio_open_stat = 0;
    s_aud_dac_state = AUDIO_DAC_NORM;
    s_current_aud_dac_state = AUDIO_DAC_NORM;
    s_current_aud_dac_sample_rate = freq;

#if CONFIG_ANC_ENABLE == 1
    if (freq_changed && app_anc_status_get())
    {
        app_anc_enable(0);
#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_MCU
        audio_dac_enable(0);
#endif

        if (apll_freq != system_apll_freq())
            app_anc_freq_changed(apll_freq);
    }
#endif

#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_MCU
    if (freq_changed)
    {
        system_apll_config(apll_freq);
        audio_dac_sample_rate_set(freq);
    }
    audio_dac_ctrl_blk.channels = channels;
    rb_init(&audio_dac_ctrl_blk.aud_rb, (uint8_t *)audio_dac_ctrl_blk.data_buff, AUDIO_DAC_BUFF_LEN, 1, audio_dac_ctrl_blk.dma_handle);
    dma_channel_enable(audio_dac_ctrl_blk.dma_handle, 1);
    dma_channel_enable(audio_dac_ctrl_blk.dma_handle, 0);
    memset(audio_dac_ctrl_blk.data_buff, 0, AUDIO_DAC_BUFF_LEN);
    aud_dac_fill_buffer((uint8_t *)audio_dac_ctrl_blk.data_buff, ((freq > 16000) ? (AUDIO_DAC_BUFF_LEN >> 1) : 1024)); // will increase delay in sco
    aud_mute_func_init(6, 9);
    audio_dac_enable(1);
#else
    mailbox_mcu2dsp_send_until_recv(MAILBOX_CMD_AUDIO_DAC_CONFIG | MAILBOX_CMD_FAST_RSP_FLAG, freq, channels, bits_per_sample);
#endif

#if CONFIG_ANC_ENABLE == 1
    if (freq_changed && app_anc_status_get())
        app_anc_enable(1);
#endif

    LOG_I(DRV, "audio_dac_config(%d, %d, %d)\r\n", freq, channels, bits_per_sample);

    return (0);
}

void aud_dac_open(void)
{
    if (s_audio_open_stat)
        return;

#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_MCU
    //audio_dac_enable(1);
    dma_channel_enable(audio_dac_ctrl_blk.dma_handle, 1);
#else
    mailbox_mcu2dsp_send_until_recv(MAILBOX_CMD_AUDIO_DAC_ENABLE | MAILBOX_CMD_FAST_RSP_FLAG, 1, 0, 0);
#endif

    aud_volume_mute(0);

    s_audio_open_stat = 1;

    LOG_I(DRV, "audio dac open\r\n");
    aud_PAmute_delay_operation(0);

#ifdef A2DP_MPEG_AAC_DECODE
    if (A2DP_CODEC_MPEG_AAC == a2dp_get_codec_type())
    {
        extern result_t bt_a2dp_aac_stream_sync(uint32_t type);
        bt_a2dp_aac_stream_sync(0);
    }
#endif
}

void aud_dac_close(void)
{
    if (!s_audio_open_stat)
        return;
    s_audio_open_stat = 0;
    aud_PAmute_delay_operation(1);
    set_flag_sbc_buffer_play(0);
#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_MCU
    dma_channel_enable(audio_dac_ctrl_blk.dma_handle, 0);
#endif

#if (CONFIG_AUD_FADE_IN_OUT == 1)
    set_aud_fade_in_out_state(AUD_FADE_NONE);
#endif

#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_MCU
#if CONFIG_ANC_ENABLE == 1
    if (app_anc_status_get() == ANC_STATUS_IDLE)
#endif
        audio_dac_enable(0);
#else
    mailbox_mcu2dsp_send_until_recv(MAILBOX_CMD_AUDIO_DAC_ENABLE | MAILBOX_CMD_FAST_RSP_FLAG, 0, 0, 0);
#endif

    LOG_I(DRV, "audio dac close\r\n");
}

void aud_dac_dig_volume_fade_in(void)
{
    g_soft_dig_gain = 0;
}

#if (CONFIG_DAC_CLOSE_IN_IDLE == 1)
void aud_dac_close_in_idle(void)
{
#if CONFIG_ANC_ENABLE == 1
    if (app_anc_status_get())
        return;
#endif

    if (!app_bt_flag1_get(APP_AUDIO_WORKING_FLAG_SET) && !(get_system_idle_cnt()))
    {
        aud_dac_close();
    }
}
#endif

uint8_t get_audio_dac_clk_state(void)
{
    return s_aud_dac_state;
}

void aud_dac_clk_set_default(void)
{
    uint8_t sbc_node_stat = sbc_node_buff_monitor();
    uint8_t sbc_freq = (sbc_node_stat >> 2) & 0x01;
    uint32_t *p_dac_clk_coef = s_aud_dac_fraccoef[sbc_freq];
    M510_AUD_DAC_FRACCOEF = 0x80000000 | p_dac_clk_coef[1];
}

void aud_dac_clk_set_coef(uint32_t clk_val)
{
    M510_AUD_DAC_FRACCOEF = 0x80000000 | clk_val;
}

void aud_dac_clk_process(void)
{
    uint8_t sbc_node_stat = sbc_node_buff_monitor();
    uint8_t sbc_freq = (sbc_node_stat >> 2) & 0x01;
    uint8_t sbc_clk = (sbc_node_stat & 0x03);
    uint32_t *p_dac_clk_coef = s_aud_dac_fraccoef[sbc_freq];
    //extern app_sbc_t app_sbc; os_printf("%d, %d\n", sbc_clk, app_sbc.sbc_ecout); return;

    switch (s_aud_dac_state)
    {
    case AUDIO_DAC_NORM:
        if (s_current_aud_dac_state != AUDIO_DAC_NORM)
        {
            M510_AUD_DAC_FRACCOEF = 0x80000000 | p_dac_clk_coef[1];
        }
        s_current_aud_dac_state = AUDIO_DAC_NORM;
        if (sbc_clk == 0)
        {
            s_aud_dac_state = AUDIO_DAC_SLOW; // Local CLK is slow
        }
        else if (sbc_clk == 2)
        {
            s_aud_dac_state = AUDIO_DAC_FAST; // Local CLK is fast
        }
        break;
    case AUDIO_DAC_SLOW:
        if (s_current_aud_dac_state != AUDIO_DAC_SLOW)
        {
            M510_AUD_DAC_FRACCOEF = 0x80000000 | p_dac_clk_coef[2]; //AUDIO_DIV_441K_SLOW;
        }
        s_current_aud_dac_state = AUDIO_DAC_SLOW;
        if (sbc_clk == 0)
        {
            s_aud_dac_state = AUDIO_DAC_SLOWER; // Local CLK is very slow
        }
        else if (sbc_clk == 2)
        {
            s_aud_dac_state = AUDIO_DAC_NORM; // Local CLk between norm and slow
        }

        break;
    case AUDIO_DAC_SLOWER:
        if (s_current_aud_dac_state != AUDIO_DAC_SLOWER)
        {
            M510_AUD_DAC_FRACCOEF = 0x80000000 | (p_dac_clk_coef[2] + DAC_CLK_ADJUST_STEP);
        }
        s_current_aud_dac_state = AUDIO_DAC_SLOWER;
        if (sbc_clk == 0)
        {
            s_aud_dac_state = AUDIO_DAC_SLOWER; // Local clk is very slow,but not follow the mobile yet;
        }
        else if (sbc_clk == 2)
        {
            s_aud_dac_state = AUDIO_DAC_SLOW; // Local clk between  veryslow and slow
        }
        break;
    case AUDIO_DAC_FAST:
        if (s_current_aud_dac_state != AUDIO_DAC_FAST)
        {
            M510_AUD_DAC_FRACCOEF = 0x80000000 | p_dac_clk_coef[0];
        }
        s_current_aud_dac_state = AUDIO_DAC_FAST;
        if (sbc_clk == 0)
        {
            s_aud_dac_state = AUDIO_DAC_NORM; // Local clk between fast and norm
        }
        else if (sbc_clk == 2)
        {
            s_aud_dac_state = AUDIO_DAC_FASTER; // Local clk is very fast
        }
        break;
    case AUDIO_DAC_FASTER:
        if (s_current_aud_dac_state != AUDIO_DAC_FASTER)
        {
            M510_AUD_DAC_FRACCOEF = 0x80000000 | (p_dac_clk_coef[0] - DAC_CLK_ADJUST_STEP);
        }
        s_current_aud_dac_state = AUDIO_DAC_FASTER;
        if (sbc_clk == 0)
        {
            s_aud_dac_state = AUDIO_DAC_FAST; // Local clk between veryfast and fast
        }
        else if (sbc_clk == 2)
        {
            s_aud_dac_state = AUDIO_DAC_FASTER; // Local clk is very fast,but not follow the mobile yet;
        }
        break;
    default:
        break;
    }
}

void aud_dac_set_volume(int8_t volume)
{
    LOG_I(VOL, "volume:%d\n", volume);
    aud_volume_t *vol_tbl_ptr;
    uint32_t ana_gain = 0;
    int16 dig_gain = 0;

    app_env_handle_t env_h = app_env_get_handle();

#ifdef CONFIG_APP_EQUANLIZER
    if (env_h->env_cfg.aud_eq.eq_enable)
    {
        dig_gain = (int16)env_h->env_cfg.aud_eq.eq_gain;
    }
#endif

#if (CONFIG_BLUETOOTH_EN == 1)
    if (hfp_has_sco() || app_bt_flag1_get(APP_FLAG_WAVE_PLAYING))
#else
    if (app_bt_flag1_get(APP_FLAG_WAVE_PLAYING))
#endif
    {
        vol_tbl_ptr = (aud_volume_t *)&env_h->env_cfg.feature.hfp_vol;
#ifdef CONFIG_APP_EQUANLIZER
        dig_gain = 0;
#endif
    }
#ifdef CONFIG_LINEIN_FUNCTION
    else if (app_bt_flag1_get(APP_FLAG_LINEIN) && (!app_bt_flag2_get(APP_FLAG2_STEREO_WORK_MODE)))
    {
        vol_tbl_ptr = (aud_volume_t *)&env_h->env_cfg.feature.linein_vol;
    }
#endif
    else
    {
        vol_tbl_ptr = (aud_volume_t *)&env_h->env_cfg.feature.a2dp_vol;
    }

    ana_gain = (vol_tbl_ptr[volume & 0x1F].ana_dig_gain) >> 13;
    dig_gain = (vol_tbl_ptr[volume & 0x1F].ana_dig_gain) & 0x1fff;
#ifdef CONFIG_APP_EQUANLIZER
    if (dig_gain < 0)
        dig_gain = 0;
#endif

    app_bt_flag2_set(APP_FLAG2_SW_MUTE, !volume);

    if (volume > 0)
    {
        aud_PAmute_operation(0);
        if (volume > AUDIO_VOLUME_MAX)
            volume = AUDIO_VOLUME_MAX;
    }
    else
    {
        aud_PAmute_operation(1);
        if (volume <= AUDIO_VOLUME_MIN)
            volume = AUDIO_VOLUME_MIN;
    }

    g_soft_dig_goal = dig_gain;
    (void)ana_gain;
}

void aud_dac_volume_control(uint8_t *buff, uint32_t size)
{
    app_env_handle_t env_h = app_env_get_handle();
    uint8_t flag_L_is_LplusR = !!(env_h->env_cfg.system_para.system_flag & APP_ENV_SYS_FLAG_L_is_LplusR);
    int32 *smpl = (int32 *)buff;
    int32_t smpl32_L, smpl32_R;
    int16_t k;

    {
        if (flag_L_is_LplusR) // L = R = L + R;
        {
            for (k = 0; k < (size >> 3); k++)
            {
                if (g_soft_dig_gain < g_soft_dig_goal)
                    g_soft_dig_gain++;
                else if (g_soft_dig_gain > g_soft_dig_goal)
                    g_soft_dig_gain--;

                smpl32_L = (*(smpl + 2 * k) >> 8) * g_soft_dig_gain;
                smpl32_R = (*(smpl + 2 * k + 1) >> 8) * g_soft_dig_gain;

                smpl32_L = (smpl32_L + smpl32_R + 1) >> 1;
                *(smpl + 2 * k) = smpl32_L;
                *(smpl + 2 * k + 1) = smpl32_L;
            }
        }
        else
        {
            for (k = 0; k < (size >> 3); k++)
            {
                if (g_soft_dig_gain < g_soft_dig_goal)
                    g_soft_dig_gain++;
                else if (g_soft_dig_gain > g_soft_dig_goal)
                    g_soft_dig_gain--;

                smpl32_L = (*(smpl + 2 * k) >> 8) * g_soft_dig_gain;
                smpl32_R = (*(smpl + 2 * k + 1) >> 8) * g_soft_dig_gain;

                *(smpl + 2 * k) = smpl32_L;
                *(smpl + 2 * k + 1) = smpl32_R;
            }
        }
    }

#if (CONFIG_AUD_FADE_IN_OUT == 1)
    {
        extern int16_t s_fade_scale;
        if (get_aud_fade_in_out_state() & (AUD_FADE_IN | AUD_FADE_OUT))
        {
            for (k = 0; k < (size >> 3); k++)
            {
                smpl32_L = (*(smpl + 2 * k) >> 8) * g_soft_dig_gain * s_fade_scale;
                smpl32_R = (*(smpl + 2 * k + 1) >> 8) * g_soft_dig_gain * s_fade_scale;
                *(smpl + 2 * k) = smpl32_L >> AUD_FADE_SCALE_LEFT_SHIFT_BITS;
                *(smpl + 2 * k + 1) = smpl32_R >> AUD_FADE_SCALE_LEFT_SHIFT_BITS;
            }
        }
    }
#endif
}

void aud_dac_fill_buffer(uint8_t *buff, uint16_t size)
{
#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_MCU
    rb_fill_buffer(&audio_dac_ctrl_blk.aud_rb, buff, size, DAC_FILL_WITH_COMP);
#else
    aud_dac_volume_control(buff, size);
    mailbox_mcu2dsp_send_until_recv(MAILBOX_CMD_AUDIO_DAC_BUF_WRITE | MAILBOX_CMD_FAST_RSP_FLAG, (uint32_t)buff, (uint32_t)size, 0);
#endif
}

void DRAM_CODE adio_sco_fill_buffer(uint8_t *buff, uint8_t fid, uint16_t size)
{
#if (CONFIG_HFP_SPK_EQ == 1)
    hfp_spk_eq_proc((uint8 *)buff, size);
#endif

    uint16_t i = 0;
    int32_t buff_st[48 * 10 * 2];
    int32_t *dst = (int32_t *)buff_st;
    uint8_t *src = (uint8_t *)buff;

    while (i < size)
    {
        int32 t = (*(src + i) << 16) | (*(src + i + 1) << 24);

        t >>= 8;
        *dst++ = t;
        *dst++ = t;
        i += 2;
    }

    aud_dac_fill_buffer((uint8_t *)buff_st, size * 4);
}

uint16_t aud_dac_get_fill_buffer_size(void)
{
#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_MCU
    return rb_get_buffer_fill_size(&audio_dac_ctrl_blk.aud_rb);
#else
    mailbox_mcu2dsp_send_until_recv(MAILBOX_CMD_AUDIO_DAC_FILL_BUF_SIZE_CHECK | MAILBOX_CMD_FAST_RSP_FLAG, 0, 0, 0);
    return mailbox_dsp2mcu_ack_get(MAILBOX_CMD_REG_IDX_PARAM0);
#endif
}

uint16_t aud_dac_get_free_buffer_size(void)
{
#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_MCU
    return rb_get_buffer_free_size(&audio_dac_ctrl_blk.aud_rb);
#else
    mailbox_mcu2dsp_send_until_recv(MAILBOX_CMD_AUDIO_DAC_FREE_BUF_SIZE_CHECK | MAILBOX_CMD_FAST_RSP_FLAG, 0, 0, 0);
    return mailbox_dsp2mcu_ack_get(MAILBOX_CMD_REG_IDX_PARAM0);
#endif
}

void aud_dac_buffer_clear(void)
{
#if CONFIG_DAC_CTRL_MODE == DAC_CTRL_BY_MCU
    ring_buffer_clear(&audio_dac_ctrl_blk.aud_rb);
#else
//TODO
#endif
}

int aud_mic_config(uint32_t freq, uint32_t channels, uint32_t bits_per_sample)
{
#if CONFIG_ADC_CTRL_MODE == ADC_CTRL_BY_MCU
    audio_adc_sample_rate_set(freq);
    audio_adc_ctrl_blk.channels = channels;
    rb_init(&audio_adc_ctrl_blk.aud_rb, (uint8_t *)audio_adc_ctrl_blk.data_buff, AUDIO_ADC_BUFF_LEN, 2, audio_adc_ctrl_blk.dma_handle);
#else
    mailbox_mcu2dsp_send_until_recv(MAILBOX_CMD_AUDIO_ADC_CONFIG | MAILBOX_CMD_FAST_RSP_FLAG, freq, channels, bits_per_sample);
#endif

    LOG_I(DRV, "audio_mic_config(%d, %d, %d)\r\n", freq, channels, bits_per_sample);

    return 0;
}

void aud_mic_open(int enable)
{
#if CONFIG_ADC_CTRL_MODE == ADC_CTRL_BY_MCU
    audio_adc_enable(enable);
    dma_channel_enable(audio_adc_ctrl_blk.dma_handle, enable);
#else
    mailbox_mcu2dsp_send_until_recv(MAILBOX_CMD_AUDIO_ADC_ENABLE | MAILBOX_CMD_FAST_RSP_FLAG, enable, 0, 0);
#endif

    LOG_I(DRV, "audio_mic_open(%d)\r\n", enable);
}

void aud_mic_set_volume(uint8_t volume)
{
}

void aud_mic_mute(uint8_t enable)
{
    //TODO
}

uint16_t aud_mic_get_fill_buffer_size(void)
{
#if CONFIG_ADC_CTRL_MODE == ADC_CTRL_BY_MCU
    return rb_get_buffer_fill_size(&audio_adc_ctrl_blk.aud_rb);
#else
    mailbox_mcu2dsp_send_until_recv(MAILBOX_CMD_AUDIO_ADC_FILL_BUF_SIZE_CHECK | MAILBOX_CMD_FAST_RSP_FLAG, 0, 0, 0);
    return mailbox_dsp2mcu_ack_get(MAILBOX_CMD_REG_IDX_PARAM0);
#endif
}

uint32_t aud_mic_read_buffer(uint8_t *buf, uint16_t len)
{
#if CONFIG_ADC_CTRL_MODE == ADC_CTRL_BY_MCU
    return rb_read_buffer(&audio_adc_ctrl_blk.aud_rb, buf, len);
#else
    mailbox_mcu2dsp_send_until_recv(MAILBOX_CMD_AUDIO_ADC_BUF_READ | MAILBOX_CMD_FAST_RSP_FLAG, (uint32_t)buf, (uint32_t)len, 0);
    return mailbox_dsp2mcu_ack_get(MAILBOX_CMD_REG_IDX_PARAM2);
#endif
}
uint16_t aud_dsp_dac_data_get_fill_buffer_size(void)
{
#if CONFIG_ADC_CTRL_MODE == ADC_CTRL_BY_MCU
    return rb_get_buffer_fill_size(&audio_adc_ctrl_blk.aud_rb);
#else
    mailbox_mcu2dsp_send_until_recv(MAILBOX_CMD_AUDIO_DAC_DATA_FILL_BUF_SIZE_CHECK | MAILBOX_CMD_FAST_RSP_FLAG, 0, 0, 0);
    return mailbox_dsp2mcu_ack_get(MAILBOX_CMD_REG_IDX_PARAM0);
#endif
}
uint32_t aud_dsp_dac_data_read_buffer(uint8_t *buf, uint16_t len)
{
#if CONFIG_ADC_CTRL_MODE == ADC_CTRL_BY_MCU
    return rb_read_buffer(&audio_adc_ctrl_blk.aud_rb, buf, len);
#else
    mailbox_mcu2dsp_send_until_recv(MAILBOX_CMD_AUDIO_DAC_DATA_BUF_READ | MAILBOX_CMD_FAST_RSP_FLAG, (uint32_t)buf, (uint32_t)len, 0);
    return mailbox_dsp2mcu_ack_get(MAILBOX_CMD_REG_IDX_PARAM2);
#endif
}

uint8_t DRAM_CODE aud_discard_sco_data(void)
{
    if (app_bt_flag1_get(APP_FLAG_WAVE_PLAYING))
    {
        return 1;
    }
    else if (app_env_check_feature_flag(APP_ENV_FEATURE_FLAG_DISABLE_IOS_INCOMING_RING) && app_bt_flag2_get(APP_FLAG2_HFP_INCOMING) && !app_bt_flag1_get(APP_FLAG_CALL_ESTABLISHED))
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

void aud_volume_mute(uint8_t enable)
{
    //TODO
}

/******************************************************/

void extPA_set_req(uint8_t open_req)
{ /* TODO */
}
void extPA_open(uint8_t delay_enable)
{ /* TODO */
}
void extPA_close(uint8_t delay_enable)
{ /* TODO */
}

/******************************************************/

#define MUTE_LOW_THD 2
#define MUTE_HIGH_THD 7

static aud_mute_cfg_t aud_mute_cfg;
static int8_t mute_fast_shift = 6; // range: 3 - 10
static int8_t mute_slow_shift = 9; // range: 5 - 12
static uint8_t mute_state = 0;
static uint32_t mute_amp = 0;

void aud_mute_init(void)
{
    app_env_handle_t env_h = app_env_get_handle();

    if (env_h->env_cfg.used == 0x01)
    {
        aud_mute_cfg.mute_pin = app_env_get_pin_num(PIN_paMute);
        aud_mute_cfg.mute_high_flag = app_env_get_pin_valid_level(PIN_paMute);
        aud_mute_cfg.mute_status = 2;
        aud_mute_cfg.mute_outside = app_env_get_pin_enable(PIN_paMute);
        aud_mute_cfg.shade_flag = 0; //((env_h->env_cfg.system_para.system_flag & APP_ENV_SYS_FLAG_SHADE_OUT) >> 10 );
        aud_mute_cfg.auto_mute_flag = (!!(env_h->env_cfg.feature.feature_flag & APP_ENV_FEATURE_FLAG_FAST_MUTE));
    }
    else
    {
        aud_mute_cfg.mute_pin = PAMUTE_GPIO_PIN;
        aud_mute_cfg.mute_high_flag = 0;
        aud_mute_cfg.mute_status = 2;
        aud_mute_cfg.mute_outside = 0;
        aud_mute_cfg.shade_flag = 0;
        aud_mute_cfg.auto_mute_flag = 0;
    }

    if (aud_mute_cfg.mute_outside)
    {
        gpio_config(aud_mute_cfg.mute_pin, 1);
        gpio_output(aud_mute_cfg.mute_pin, !!aud_mute_cfg.mute_high_flag);
    }
}

void aud_mute_func_init(int8_t fast_shift, int8_t slow_shift)
{
    mute_fast_shift = fast_shift;
    mute_slow_shift = slow_shift;
}

void aud_mute_update(int16_t samplel, int16_t sampler)
{
    if (aud_mute_cfg.auto_mute_flag)
    {
        int8_t mute_shift;
        uint32_t abs_samplel = (ABS(samplel) << 16);
        uint32_t abs_sampler = (ABS(sampler) << 16);
        uint32_t mute_tmp = mute_amp;
        uint32_t abs_sample = (abs_samplel >> 1) + (abs_sampler >> 1);

        mute_shift = abs_sample > mute_amp ? mute_fast_shift : mute_slow_shift;

        mute_amp -= (mute_amp >> mute_shift);
        mute_amp += (abs_sample >> mute_shift);

        mute_tmp = mute_amp >> 16;

        if (mute_tmp > MUTE_HIGH_THD && mute_state == 0)
        {
            mute_state = 1;
            aud_PAmute_operation(0);
            app_bt_flag2_set(APP_FLAG2_MUTE_FUNC_MUTE, 0);
        }
        else if (mute_tmp < MUTE_LOW_THD && mute_state == 1)
        {
            mute_state = 0;
            aud_PAmute_operation(1);
            app_bt_flag2_set(APP_FLAG2_MUTE_FUNC_MUTE, 1);
        }
    }
}

/*  1 -- direct PA mute  0 -- delay PA unmute */
void aud_PAmute_operation(int enable)
{
    if (!aud_mute_cfg.mute_outside)
        return;

    if (enable && (aud_mute_cfg.mute_status != 1))
    {
        //os_delay_ms(0);
        if (s_audio_open_stat)
            return; //Can't mute if DAC is opening
        if (app_get_audio_task_handle() != NULL)
            jtask_stop(app_get_audio_task_handle());

        if (aud_mute_cfg.mute_high_flag) // bit7 = 1: high effect
            gpio_output(aud_mute_cfg.mute_pin, 1);
        else
            gpio_output(aud_mute_cfg.mute_pin, 0);
        os_printf("PA mute\r\n");
        mute_state = 0;
    }
    else if ((0 == enable) && (aud_mute_cfg.mute_status != 0))
    {
        if (app_bt_flag1_get(APP_FLAG_POWERDOWN) ||
            !s_audio_open_stat) //Can't unmute if DAC is closing
            return;
        if (aud_mute_cfg.mute_high_flag) // bit7 = 1: high effect
            gpio_output(aud_mute_cfg.mute_pin, 0);
        else
            gpio_output(aud_mute_cfg.mute_pin, 1);
        os_printf("PA unmute\r\n");
        mute_state = 1;
    }

    aud_mute_cfg.mute_status = enable;

    return;
}

void aud_PAmute_delay_operation(int enable)
{
    app_env_handle_t env_h = app_env_get_handle();
    if (enable)
    {
        aud_PAmute_operation(1);
        if (env_h->env_cfg.feature.pa_mute_delay_time)
            os_delay_ms((10 * env_h->env_cfg.feature.pa_mute_delay_time));
    }
    else
    {
        if (env_h->env_cfg.feature.pa_unmute_delay_time)
            os_delay_ms((10 * env_h->env_cfg.feature.pa_unmute_delay_time));
        aud_PAmute_operation(0);
    }
}

/******************************************************/

#if (CONFIG_AUD_FADE_IN_OUT == 1)
int16_t s_fade_scale = 0;
static t_aud_fade_state s_aud_fade_status = AUD_FADE_NONE;

__INLINE__ void set_aud_fade_in_out_state(t_aud_fade_state state)
{
    if (state == AUD_FADE_IN)
        s_fade_scale = AUD_FADE_SCALE_MIN;
    else if (state == AUD_FADE_OUT)
        s_fade_scale = AUD_FADE_SCALE_MAX;
    s_aud_fade_status = state;
}

__INLINE__ t_aud_fade_state get_aud_fade_in_out_state(void)
{
    return s_aud_fade_status;
}

void aud_fade_status_debug(void)
{
    os_printf("---------Fade in/out status------------\r\n");
    os_printf("| Fade in/out state:%d\r\n", s_aud_fade_status);
    os_printf("| Fade in/out step :%d\r\n", s_fade_scale);
    os_printf("---------Fade in/out end---------------\r\n");
}

void aud_fade_in_out_process(void)
{
    t_aud_fade_state status = get_aud_fade_in_out_state();

    if (AUD_FADE_IN == status)
    {
        s_fade_scale += AUD_FADE_STEP;
        if (s_fade_scale >= AUD_FADE_SCALE_MAX)
        {
            set_aud_fade_in_out_state(AUD_FADE_FINISHED);
        }
    }
    else if (AUD_FADE_OUT == status)
    {
        s_fade_scale -= AUD_FADE_STEP;
        if (s_fade_scale <= AUD_FADE_SCALE_MIN)
        {
            set_aud_fade_in_out_state(AUD_FADE_FINISHED);
        }
    }
    else
    {
        set_aud_fade_in_out_state(AUD_FADE_NONE);
    }
}
#endif

/******************************************************/

#if A2DP_ROLE_SOURCE_CODE

typedef struct _driver_lineindata_s
{
    driver_ringbuff_t data_rb;
} DRIVER_LINEINDATA_T;

driver_ringbuff_t *getLineRingbuf(void);

DRIVER_LINEINDATA_T lineinDataBlk;

driver_ringbuff_t *getLineRingbuf(void)
{
    return &lineinDataBlk.data_rb;
}

void RAM_CODE audLineinFillBuffer(uint8_t *buff, uint16_t size)
{
    //os_printf("f.b. %d \r\n", size);
    rb_fill_buffer(getLineRingbuf(), buff, size, LINEIN_FILL);
}

void RAM_CODE dacClkAdjust(int mode)
{
    switch (mode)
    {
    case 1:                                                       //fast
        M510_AUD_DAC_FRACCOEF -= M510_AUD_DAC_FRACCOEF >> 16; //15.258ppm
        break;
    case 3:                                                       //fast fast
        M510_AUD_DAC_FRACCOEF -= M510_AUD_DAC_FRACCOEF >> 14; // 4*15.258ppm
        break;
    case 2:                                                       //slow
        M510_AUD_DAC_FRACCOEF += M510_AUD_DAC_FRACCOEF >> 16; //15.258ppm
        break;
    case 4:                                                       //slow slow
        M510_AUD_DAC_FRACCOEF += M510_AUD_DAC_FRACCOEF >> 14; // 4*15.258ppm
        break;
    case 0:
    default:
        if ((M510_AUD_AUDIO_CONF & 0x3) == 2) // 44.1k
            M510_AUD_DAC_FRACCOEF = AUDIO_DIV_441K;
        else
            M510_AUD_DAC_FRACCOEF = AUDIO_DIV_48K;
        break;
    }
}

#endif

/******************************************************/

#if (CONFIG_APP_MSBC_RESAMPLE == 1)

int16_t fir_coef[NFIR] = {
    12,
    -2,
    -15,
    -3,
    20,
    12,
    -26,
    -27,
    27,
    50,
    -21,
    -79,
    0,
    110,
    40,
    -135,
    -103,
    144,
    190,
    -123,
    -296,
    56,
    415,
    75,
    -536,
    -303,
    648,
    697,
    -739,
    -1518,
    798,
    5137,
    7369,
    5137,
    798,
    -1518,
    -739,
    697,
    648,
    -303,
    -536,
    75,
    415,
    56,
    -296,
    -123,
    190,
    144,
    -103,
    -135,
    40,
    110,
    0,
    -79,
    -21,
    50,
    27,
    -27,
    -26,
    12,
    20,
    -3,
    -15,
    -2,
    12,
};
int16_t b_coef[N_IIR] = {
    125, 822, 2878, 6868, 12268, 17137, 19117, 17137, 12268, 6868, 2878, 822, 125};
int16_t a_coef[N_IIR] = {
    4096, 7223, 14909, 17593, 19093, 15553, 10841, 6022, 2727, 958, 251, 44, 4};

int16_t fir_hardcore_init(void)
{
    int16_t i;
    int16_t *coef = (int16_t *)&fir_coef[0];
    M510_PMU_PERI_PWDS &= ~bit_PMU_FFT_PWD;
    M510_FFT_FFT_CONF = 0x00;
    M510_FFT_FIR_CONF = (NFIR + 1) | (1L << sft_FIR_CONF_FIR_ENABLE);
    //M510_FFT_FIR_CONF = (CORE_NFIR) | (1L<<sft_FIR_CONF_FIR_MODE) | (1L<<sft_FIR_CONF_FIR_ENABLE);
    for (i = 0; i < NFIR; i++)
    {
        M510_FFT_COEF_PORT = coef[i];
    }
    return 0;
}
int16_t fir_hardcore_close(void)
{
    M510_FFT_FIR_CONF = 0x00;
    M510_PMU_PERI_PWDS |= bit_PMU_FFT_PWD;
    return 0;
}
int16_t fir_hardcore_filter(int16_t *smpl, uint16_t nSmpls)
{
    uint16_t i;
    int32_t tmp;
    for (i = 0; i < nSmpls; i++)
    {
        M510_FFT_DATA_PORT = smpl[i];
        M510_FFT_FFT_START = 0x01;
        while (!(M510_FFT_FFT_STATUS & bit_FFT_STATUS_FIR_DONE))
            ;
        tmp = M510_FFT_DATA_PORT;
        smpl[i] = (tmp & 0xffff);
    }
    return 0;
}
int16_t FIR_sw_filter_init(pFIR_STATE p_fir_st)
{
    unsigned int i;
    p_fir_st->coef = &fir_coef[0];
    p_fir_st->taps = NFIR;
    p_fir_st->curr_pos = NFIR - 1;
    p_fir_st->ratio = 0;
    for (i = 0; i < NFIR; i++)
    {
        p_fir_st->laststate[i] = 0;
    }
    return 0;
}
static int16_t fir_sw_filter_sample(pFIR_STATE pfir_stat, int16_t smpl)
{
    int16_t i;
    int32_t y;
    int16_t offset1;
    int16_t offset2;
    pfir_stat->laststate[pfir_stat->curr_pos] = smpl;
    offset2 = pfir_stat->curr_pos;
    offset1 = pfir_stat->taps - offset2;
    y = 0;
    for (i = pfir_stat->taps - 1; i >= offset1; i--)
        y += pfir_stat->coef[i] * pfir_stat->laststate[i - offset1];

    for (; i >= 0; i--)
        y += pfir_stat->coef[i] * pfir_stat->laststate[i + offset2];

    if (pfir_stat->curr_pos <= 0)
        pfir_stat->curr_pos = pfir_stat->taps;
    pfir_stat->curr_pos--;
    y >>= 14;
    if (y > 32767)
        y = 32767;
    else if (y < -32768)
        y = -32768;
    return y;
}
int16_t FIR_sw_filter_exe(pFIR_STATE p_fir_st, int16_t *in_smpl, int16_t *out_smpl, int16_t len)
{
    int16_t i;
    for (i = 0; i < len; i++)
    {
        out_smpl[i] = fir_sw_filter_sample(p_fir_st, in_smpl[i]);
    }
    return 0;
}
void IIR_filter_init(t_IIR_State *st)
{
    int16_t i;
    st->a = (int16_t *)&a_coef[0];
    st->b = (int16_t *)&b_coef[0];
    for (i = 0; i < N_IIR; i++)
    {
        st->y[i] = 0;
        st->x[i] = 0;
    }
}
void IIR_filter_exe(t_IIR_State *st, int16_t *x, int16_t *y, int16_t len)
{
    int16_t i, k;
    int32_t smpl_tmp;
    for (i = 0; i < len; i++)
    {
        // Shift the register values.
        for (k = N_IIR - 1; k > 0; k--)
            st->x[k] = st->x[k - 1];
        for (k = N_IIR - 1; k > 0; k--)
            st->y[k] = st->y[k - 1];

        st->x[0] = x[i];
        smpl_tmp = st->b[0] * st->x[0];
        for (k = 1; k < N_IIR; k++)
        {
            smpl_tmp += (st->b[k] * st->x[k] - st->a[k] * st->y[k]);
        }
        smpl_tmp >>= 12;
        if (smpl_tmp > 32767)
            smpl_tmp = 32767;
        else if (smpl_tmp < -32768)
            smpl_tmp = -32768;

        st->y[0] = smpl_tmp;
        // a[0] should = 1
        y[i] = st->y[0];
    }
}

#endif

#ifdef CONFIG_APP_EQUANLIZER
#if (CONFIG_PRE_EQ == 1)
aud_pre_equ_t aud_pre_eqe;
extern SAMPLE_ALIGN aud_pre_equ_para_t tbl_eq_coef[];
void app_set_pre_eq_gain(uint8_t *para)
{
    uint16_t tmp_gain;

    tmp_gain = para[0] | para[1] << 8 | para[2] << 16 | para[3] << 24;
    os_printf("%02x, %02x %x\r\n", para[0], para[1], tmp_gain);
    aud_pre_eqe.globle_gain = (uint32_t)tmp_gain;
}

#define CMD_AUD_EQ_OPEN 0xF0
#define CMD_AUD_EQ_CLOSE 0xF1
#define CMD_AUD_EQ_RST_PARA 0xF2

void app_set_pre_eq(uint8_t *para)
{
    int i;
#if 1
    if (para[0] == 0) //first bands
    {
        aud_pre_eqe.totle_EQ = 0;
    }
    else if (para[0] == CMD_AUD_EQ_OPEN)
        aud_pre_eqe.online_flag = 0x5a;
    else if (para[0] == CMD_AUD_EQ_CLOSE) //close EQ
        aud_pre_eqe.online_flag = 0;
    else if (para[0] == CMD_AUD_EQ_RST_PARA)
    {
        aud_pre_eqe.totle_EQ = 0;
        for (i = 0; i < CON_AUD_EQ_BANDS; i++)
        {
            tbl_eq_coef[i].a[0] = 0;
            tbl_eq_coef[i].a[1] = 0;
            tbl_eq_coef[i].b[0] = 0x100000;
            tbl_eq_coef[i].b[1] = 0;
            tbl_eq_coef[i].b[2] = 0;
        }
    }
    if (para[0] >= CON_AUD_EQ_BANDS)
        return;

    //	os_printf("bf:%d:%x,%x,%x,%x,%x\r\n",para[0],tbl_eq_coef[para[0]].a[0],
    //		tbl_eq_coef[para[0]].a[1],
    //		tbl_eq_coef[para[0]].b[0],
    //		tbl_eq_coef[para[0]].b[1],
    //		tbl_eq_coef[para[0]].b[2]);
    if (para[1] == 0) //enable flag
    {
        tbl_eq_coef[para[0]].a[0] = 0;
        tbl_eq_coef[para[0]].a[1] = 0;
        tbl_eq_coef[para[0]].b[0] = 0x100000;
        tbl_eq_coef[para[0]].b[1] = 0;
        tbl_eq_coef[para[0]].b[2] = 0;
        return; //enable flag == 0
    }

    if (para[0] + 1 > aud_pre_eqe.totle_EQ)
        aud_pre_eqe.totle_EQ = para[0] + 1;

    memcpy(&tbl_eq_coef[para[0]].a[0], &para[2], 4 * 5);
    aud_pre_eqe.online_flag = 0x5a;
#endif
}

void app_show_pre_eq(void)
{
    int i;
    os_printf("AUD_PRE_EQ flag:0x%x,cnt:%d,gain:%d\r\n", aud_pre_eqe.online_flag, aud_pre_eqe.totle_EQ, aud_pre_eqe.globle_gain);
    for (i = 0; i < CON_AUD_EQ_BANDS; i++)
        os_printf("i:%d\r\n,%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n", i,
                  tbl_eq_coef[i].a[0],
                  tbl_eq_coef[i].a[1],
                  tbl_eq_coef[i].b[0],
                  tbl_eq_coef[i].b[1],
                  tbl_eq_coef[i].b[2]);
}

extern SAMPLE_ALIGN uint32_t s_eq_last_XY[];
void app_init_pre_eq(void)
{
    memset((uint8_t *)s_eq_last_XY, 0, 4 * 4 * CON_AUD_EQ_BANDS);
}
void app_set_eq_gain_enable(uint8 *para)
{
    app_env_handle_t env_h = app_env_get_handle();
    env_h->env_cfg.aud_eq.eq_enable = (para[1] << 8) | para[0];
    env_h->env_cfg.aud_eq.eq_gain = (para[3] << 8) | para[2];
    float V0 = powf(10, (float)env_h->env_cfg.aud_eq.eq_gain / 20);
    aud_pre_eqe.globle_gain = (uint32)((float)0x4000 * V0);
    //app_button_sw_action(BUTTON_BT_VOL_P);
}
#endif

#if (CONFIG_HFP_SPK_EQ == 1)
hfp_spk_equ_t hfp_spk_eqe;
extern SAMPLE_ALIGN hfp_spk_equ_para_t tbl_hfp_spk_eq_coef[];
void app_set_hfp_spk_eq_gain(uint8_t *para)
{
    uint16_t tmp_gain;

    tmp_gain = para[0] | para[1] << 8 | para[2] << 16 | para[3] << 24;
    os_printf("HFP_SPK_EQ %02x, %02x %x\r\n", para[0], para[1], tmp_gain);
    hfp_spk_eqe.globle_gain = (uint32_t)tmp_gain;
}

#define CMD_AUD_EQ_OPEN 0xF0
#define CMD_AUD_EQ_CLOSE 0xF1
#define CMD_AUD_EQ_RST_PARA 0xF2

void app_set_hfp_spk_eq(uint8_t *para)
{
    int i;
#if 1
    if (para[0] == 0) //first bands
    {
        hfp_spk_eqe.totle_EQ = 0;
    }
    else if (para[0] == CMD_AUD_EQ_OPEN)
        hfp_spk_eqe.online_flag = 0x5a;
    else if (para[0] == CMD_AUD_EQ_CLOSE) //close EQ
        hfp_spk_eqe.online_flag = 0;
    else if (para[0] == CMD_AUD_EQ_RST_PARA)
    {
        hfp_spk_eqe.totle_EQ = 0;
        for (i = 0; i < CON_HFP_SPK_EQ_BANDS; i++)
        {
            tbl_hfp_spk_eq_coef[i].a[0] = 0;
            tbl_hfp_spk_eq_coef[i].a[1] = 0;
            tbl_hfp_spk_eq_coef[i].b[0] = 0x100000;
            tbl_hfp_spk_eq_coef[i].b[1] = 0;
            tbl_hfp_spk_eq_coef[i].b[2] = 0;
        }
    }
    if (para[0] >= CON_HFP_SPK_EQ_BANDS)
        return;

    //	os_printf("bf:%d:%x,%x,%x,%x,%x\r\n",para[0],tbl_eq_coef[para[0]].a[0],
    //		tbl_eq_coef[para[0]].a[1],
    //		tbl_eq_coef[para[0]].b[0],
    //		tbl_eq_coef[para[0]].b[1],
    //		tbl_eq_coef[para[0]].b[2]);
    if (para[1] == 0) //enable flag
    {
        tbl_hfp_spk_eq_coef[para[0]].a[0] = 0;
        tbl_hfp_spk_eq_coef[para[0]].a[1] = 0;
        tbl_hfp_spk_eq_coef[para[0]].b[0] = 0x100000;
        tbl_hfp_spk_eq_coef[para[0]].b[1] = 0;
        tbl_hfp_spk_eq_coef[para[0]].b[2] = 0;
        return; //enable flag == 0
    }

    if (para[0] + 1 > hfp_spk_eqe.totle_EQ)
        hfp_spk_eqe.totle_EQ = para[0] + 1;

    memcpy(&tbl_hfp_spk_eq_coef[para[0]].a[0], &para[2], 4 * 5);
    hfp_spk_eqe.online_flag = 0x5a;
#endif
}

void app_show_hfp_spk_eq(void)
{
    int i;
    os_printf("HFP_SPK_EQ flag:0x%x,cnt:%d,gain:%d\r\n", hfp_spk_eqe.online_flag, hfp_spk_eqe.totle_EQ, hfp_spk_eqe.globle_gain);
    for (i = 0; i < CON_HFP_SPK_EQ_BANDS; i++)
        os_printf("i:%d\r\n,%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n", i,
                  tbl_hfp_spk_eq_coef[i].a[0],
                  tbl_hfp_spk_eq_coef[i].a[1],
                  tbl_hfp_spk_eq_coef[i].b[0],
                  tbl_hfp_spk_eq_coef[i].b[1],
                  tbl_hfp_spk_eq_coef[i].b[2]);
}

extern SAMPLE_ALIGN uint32_t s_hfp_spk_eq_last_XY[];
void app_init_hfp_spk_eq(void)
{
    memset((uint8_t *)s_hfp_spk_eq_last_XY, 0, 4 * 2 * CON_HFP_SPK_EQ_BANDS);
}
void app_set_spk_eq_gain_enable(uint8 *para)
{
    app_env_handle_t env_h = app_env_get_handle();
    env_h->env_cfg.hfp_cfg.hfp_spk_eq_enable = (para[1] << 8) | para[0];
    env_h->env_cfg.hfp_cfg.hfp_spk_eq_gain = (para[3] << 8) | para[2];
    float V0 = powf(10, (float)env_h->env_cfg.hfp_cfg.hfp_spk_eq_gain / 20);
    hfp_spk_eqe.globle_gain = (uint32)((float)0x4000 * V0);
    //app_button_sw_action(BUTTON_BT_VOL_P);
}
#endif

#if (CONIFG_HFP_MIC_EQ == 1)
hfp_mic_equ_t hfp_mic_eqe;
extern SAMPLE_ALIGN hfp_mic_equ_para_t tbl_hfp_mic_eq_coef[];
void app_set_hfp_mic_eq_gain(uint8_t *para)
{
    uint16_t tmp_gain;

    tmp_gain = para[0] | para[1] << 8 | para[2] << 16 | para[3] << 24;
    os_printf("%02x, %02x %x\r\n", para[0], para[1], tmp_gain);
    hfp_mic_eqe.globle_gain = (uint32_t)tmp_gain;
}

#define CMD_AUD_EQ_OPEN 0xF0
#define CMD_AUD_EQ_CLOSE 0xF1
#define CMD_AUD_EQ_RST_PARA 0xF2

void app_set_hfp_mic_eq(uint8_t *para)
{
    int i;
#if 1
    if (para[0] == 0) //first bands
    {
        hfp_mic_eqe.totle_EQ = 0;
    }
    else if (para[0] == CMD_AUD_EQ_OPEN)
        hfp_mic_eqe.online_flag = 0x5a;
    else if (para[0] == CMD_AUD_EQ_CLOSE) //close EQ
        hfp_mic_eqe.online_flag = 0;
    else if (para[0] == CMD_AUD_EQ_RST_PARA)
    {
        hfp_mic_eqe.totle_EQ = 0;
        for (i = 0; i < CON_HFP_MIC_EQ_BANDS; i++)
        {
            tbl_hfp_mic_eq_coef[i].a[0] = 0;
            tbl_hfp_mic_eq_coef[i].a[1] = 0;
            tbl_hfp_mic_eq_coef[i].b[0] = 0x100000;
            tbl_hfp_mic_eq_coef[i].b[1] = 0;
            tbl_hfp_mic_eq_coef[i].b[2] = 0;
        }
    }
    if (para[0] >= CON_HFP_MIC_EQ_BANDS)
        return;

    //	os_printf("bf:%d:%x,%x,%x,%x,%x\r\n",para[0],tbl_eq_coef[para[0]].a[0],
    //		tbl_eq_coef[para[0]].a[1],
    //		tbl_eq_coef[para[0]].b[0],
    //		tbl_eq_coef[para[0]].b[1],
    //		tbl_eq_coef[para[0]].b[2]);
    if (para[1] == 0) //enable flag
    {
        tbl_hfp_mic_eq_coef[para[0]].a[0] = 0;
        tbl_hfp_mic_eq_coef[para[0]].a[1] = 0;
        tbl_hfp_mic_eq_coef[para[0]].b[0] = 0x100000;
        tbl_hfp_mic_eq_coef[para[0]].b[1] = 0;
        tbl_hfp_mic_eq_coef[para[0]].b[2] = 0;
        return; //enable flag == 0
    }

    if (para[0] + 1 > hfp_mic_eqe.totle_EQ)
        hfp_mic_eqe.totle_EQ = para[0] + 1;

    memcpy(&tbl_hfp_mic_eq_coef[para[0]].a[0], &para[2], 4 * 5);
    hfp_mic_eqe.online_flag = 0x5a;
#endif
}

void app_show_hfp_mic_eq(void)
{
    int i;
    os_printf("HFP_MIC_EQ flag:0x%x,cnt:%d,gain:%d\r\n", hfp_mic_eqe.online_flag, hfp_mic_eqe.totle_EQ, hfp_mic_eqe.globle_gain);
    for (i = 0; i < CON_HFP_MIC_EQ_BANDS; i++)
        os_printf("i:%d\r\n,%d\r\n%d\r\n%d\r\n%d\r\n%d\r\n", i,
                  tbl_hfp_mic_eq_coef[i].a[0],
                  tbl_hfp_mic_eq_coef[i].a[1],
                  tbl_hfp_mic_eq_coef[i].b[0],
                  tbl_hfp_mic_eq_coef[i].b[1],
                  tbl_hfp_mic_eq_coef[i].b[2]);
}

extern SAMPLE_ALIGN uint32_t s_hfp_mic_eq_last_XY[];
void app_init_hfp_mic_eq(void)
{
    memset((uint8_t *)s_hfp_mic_eq_last_XY, 0, 4 * 2 * CON_HFP_MIC_EQ_BANDS);
}

void app_set_mic_eq_gain_enable(uint8 *para)
{
    app_env_handle_t env_h = app_env_get_handle();
    env_h->env_cfg.hfp_cfg.hfp_mic_eq_enable = (para[1] << 8) | para[0];
    env_h->env_cfg.hfp_cfg.hfp_mic_eq_gain = (para[3] << 8) | para[2];
    float V0 = powf(10, (float)env_h->env_cfg.hfp_cfg.hfp_mic_eq_gain / 20);
    hfp_mic_eqe.globle_gain = (uint32)((float)0x4000 * V0);
    //app_button_sw_action(BUTTON_BT_VOL_P);
}
#endif

#endif
